﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace Diplomova_prace
{
    /// <summary>
    /// Třída Expression slouží k převedení výrazu do postfixové notace (metoda RPN) a následnému vyčíslení výrazu pomocí Shunting Yard algoritmu(ComputeRPN)
    /// Metoda TextToMathml slouží k převedení výrazu do Mathml kódu (Přemístit metody ? - Pavlos)
    /// nahradit char znaky proměnnými
    /// </summary>
    public class Expression
    {
        const char pi = 'ê';
        char id = Convert.ToChar(235);
        public delegate void IncorrectInputHandler();
        public event IncorrectInputHandler incorrectInput;
        Dictionary<char, char> associativity = new Dictionary<char, char>() { { '+', 'L' }, { '-', 'L' }, { '*', 'L' }, { '/', 'L' }, { '^', 'R' } };
        List<string> ListofFunction = new List<string>() { { "sin" }, { "cos" }, { "tan" }, { "tg" }, { "ctg" }, { "ln" }, { "log" }, { "asin" }, { "acos" }, { "atan" }, { "actg" }, { "sqrt" } };
        List<char> ListOfOperatorLasoc = new List<char>() { { '+' }, { '-' }, { '*' }, { '/' } };

        /// <summary>
        /// Slouží pro převod matematického výrazu do postfixové notace
        /// </summary>
        /// <param name="infix"> výraz v infixové notaci</param>
        /// <returns></returns>
        public string RPN(string infix)
        {
            infix = Regex.Replace(infix, @"\s+", "").Trim();
            infix = EditSigned(infix);
            infix = Regex.Replace(infix, @"^\+", "");
            infix.Replace(',', '.');
            infix = infix.Replace('[', '(');
            infix = infix.Replace(']',')');
            infix = infix.Replace('{', '(');
            infix = infix.Replace('}', ')');
            infix = infix.ToLower();
            infix = ConvertDecNumToFraction(infix);
            infix = infix.Replace("pi", pi.ToString());
            infix = AddMultiplyOperator(infix);
            infix = PowerOperatorBracketMinus(infix);
            infix = EditPowerMinusOperator(infix);
            infix = DetectUnaryOperator(infix, '+');
            infix = DetectUnaryOperator(infix, '-');
            infix = infix.Replace("-(", "+(0-1)*(");
            infix = infix.Replace("- (", "+(0-1)*(");
            infix = Regex.Replace(infix, @"\s+", "").Trim();
            StackShunting stack = new StackShunting();
            StringBuilder postfix = new StringBuilder();
            StringBuilder function = new StringBuilder();
            for (int i = 0; i < infix.Length; i++)
            {
                if (Char.IsDigit(infix[i]) || infix[i] == 'x' || infix[i] == 'e' || infix[i] == pi)
                    postfix.Append(infix[i]);
                else if (Char.IsLetter(infix[i]))
                {
                    function.Append(infix[i]);
                    for (int j = 0; j < ListofFunction.Count; j++)
                    {
                        if (function.ToString() == ListofFunction[j])
                        {
                            stack.Push(function.ToString(), 0);
                            function.Clear();
                        }
                    }
                }
                else
                {
                    postfix.Append(" ");
                    if (infix[i] == '(')
                        stack.Push(infix[i].ToString(), 0);
                    else if (infix[i] == ')')
                    {
                        while (stack.getznakTop != "(")
                        {
                            postfix.Append(" " + stack.getznakTop + " ");
                            if (stack.getCount > 0)
                                stack.Pop();
                            else
                            {
                                incorrectInput();
                                return string.Empty;
                            }
                        }
                        stack.Pop(); // Vyjmutí levé závorky
                        for (int j = 0; j < ListofFunction.Count; j++)
                        {
                            if (stack.getznakTop == ListofFunction[j])
                            {
                                postfix.Append(ListofFunction[j]);
                                stack.Pop();
                            }
                        }
                    }
                    else if (infix[i] == '+' || infix[i] == '-' || infix[i] == '*' || infix[i] == '^' || infix[i] == '/')
                    {
                        int priorita;
                        int qpriorita;
                        if (infix[i] == '^')
                            priorita = 3;
                        else if (infix[i] == '*' || infix[i] == '/')
                            priorita = 2;
                        else
                            priorita = 1;
                        qpriorita = stack.getprioritaTop;
                        char asoc = associativity[infix[i]];
                        if (asoc == 'L')
                        {
                            while (priorita <= qpriorita && stack.getCount > 0 && (stack.getznakTop !=")" && stack.getznakTop !="("))
                            {
                                postfix.Append(" " + stack.getznakTop + " ");
                                stack.Pop();
                                qpriorita = stack.getprioritaTop;
                            }
                        }
                        else
                        {
                            while (priorita < qpriorita && stack.getCount > 0 && (stack.getznakTop != ")" && stack.getznakTop != "("))  //bez rovnítka, asociativita zleva !!!
                            {
                                postfix.Append(" " + stack.getznakTop + " ");
                                stack.Pop();
                                qpriorita = stack.getprioritaTop;
                            }
                        }
                        stack.Push(infix[i].ToString(), priorita);
                    }
                }
            }
            while (stack.getCount > 0)
            {
                if (stack.getznakTop == "(")
                {
                    incorrectInput();
                    return string.Empty;
                }
                postfix.Append(" " + stack.getznakTop + " ");
                stack.Pop();
            }
            if (function.ToString() != string.Empty)
            {
                incorrectInput();
                return string.Empty;
            }
            string result = SimplifyFraction(postfix.ToString());
            return result;
        }
        /// <summary>
        /// Vypočte hodnotu výrazu v postixové notaci( Shunting-Yard algoritmus)
        /// </summary>
        /// <param name="postfix"> Matematický výraz v postfixové notaci</param>
        /// <param name="parametr"> Hodnota parametru x v matematickém výrazu</param>
        /// <returns></returns>
        public double ComputeRPN(string postfix , double parametr = double.NaN)
        {
           Stack stack = new Stack();
            postfix = System.Text.RegularExpressions.Regex.Replace(postfix, @"\s+", " ").Trim();
            string[] expressions = postfix.Split(' ');
            double op1 = double.NaN;
            double op2 = double.NaN;
            double output = double.NaN;
            for (int i = 0; i < expressions.Length; i++)
            {
                double value = double.NaN;
                if (Double.TryParse(expressions[i], out value))
                {
                    stack.Push(value, -1);
                }
                else if (expressions[i] == pi.ToString())
                {
                    stack.Push(Math.PI, -1);
                }
                else if (expressions[i] == "e")
                {
                    stack.Push(Math.E, -1);
                }
                else if (expressions[i] == "x")
                {
                    if (parametr != double.NaN)
                        stack.Push(parametr, -1);
                    else if (double.IsNaN(parametr))
                        return double.NaN;
                }
                else
                {
                    if (expressions[i] == "+" || expressions[i] == "-" || expressions[i] == "*" || expressions[i] == "/" || expressions[i] == "^")
                    {
                        try
                        {
                            op1 = stack.getznakTop;
                            stack.Pop();
                            op2 = stack.getznakTop;
                            stack.Pop();
                        }
                        catch (Exception)
                        {
                            if (incorrectInput != null)
                                incorrectInput();
                            return double.NaN;
                        }
                        if (expressions[i] == "+")
                            output = op2 + op1;
                        else if (expressions[i] == "-")
                            output = op2 - op1;
                        else if (expressions[i] == "*")
                            output = op2 * op1;
                        else if (expressions[i] == "/")
                            output = op2 / op1;
                        else
                            output = Math.Pow(op2, op1);
                        stack.Push(output, -1);
                    }
                    else
                    {
                        if (expressions[i] == "sin" || expressions[i] == "cos" || expressions[i] == "tan" || expressions[i] == "tg" || expressions[i] == "ctg" || expressions[i] == "ln"
                            || expressions[i] == "log" || expressions[i] == "asin" || expressions[i] == "acos" || expressions[i] == "atan" || expressions[i] == "actg" || expressions[i] == "sqrt")
                        {
                            try
                            {
                                op1 = stack.getznakTop;
                                stack.Pop();
                            }
                            catch (Exception)
                            {
                                if (incorrectInput != null)
                                    incorrectInput();
                                return double.NaN;
                            }
                            if (expressions[i] == "sin")
                                output = Math.Sin(op1);
                            else if (expressions[i] == "cos")
                                output = Math.Cos(op1);
                            else if (expressions[i] == "tan" || expressions[i] == "tg")
                                output = Math.Tan(op1);
                            else if (expressions[i] == "ctg")
                                output = 1 / Math.Tan(op1);
                            else if (expressions[i] == "ln")
                                output = Math.Log(op1);
                            else if (expressions[i] == "log")
                                output = Math.Log10(op1);
                            else if (expressions[i] == "asin")
                                output = Math.Asin(op1);
                            else if (expressions[i] == "acos")
                                output = Math.Acos(op1);
                            else if (expressions[i] == "atan")
                                output = Math.Atan(op1);
                            else if (expressions[i] == "actg")
                                output = 1 / Math.Atan(op1);
                            else if (expressions[i] == "sqrt")
                                output = Math.Sqrt(op1);
                            stack.Push(output, -1);
                        }
                    }
                }
            }
            if (stack.getCount > 1)
                return double.NaN;
            else
                return stack.getznakTop;
        }
        /// <summary>
        /// Slouží pro doplnění znaku nasobení ve výrazu
        /// </summary>
        /// <param name="input">Matematický výraz v infixové notaci</param>
        /// <returns></returns>
        private string AddMultiplyOperator(string input)
        {
            // ê = pi
            string pattern = "([0-9]+)([a-zê]+)";
            bool change = true ;
            string oldInput = input;
            while (change)
            {
                input = Regex.Replace(input, pattern, "$1*$2");
                pattern = "([a-zA-Zê]+)([0-9]+)";
                input = Regex.Replace(input, pattern, "$1*$2");
                pattern = "(\\))(\\()";
                input = Regex.Replace(input, pattern, "$1*$2");
                pattern = "([0-9ê]+)(\\()";
                input = Regex.Replace(input, pattern, "$1*$2");
                pattern = "(\\))([0-9ê]+)";
                input = Regex.Replace(input, pattern, "$1*$2");
                pattern = "(\\))([a-z]+)";
                input = Regex.Replace(input, pattern, "$1*$2");
                pattern = "(\\))([x|e|ê])";
                input = Regex.Replace(input, pattern, "$1*$2");
                pattern = "([x|e|ê])(\\()";
                input = Regex.Replace(input, pattern, "$1*$2");
                pattern = "([x|e|ê])([x|e|ê])";
                input = Regex.Replace(input, pattern, "$1*$2");
                if (oldInput == input)
                    change = false;
                else 
                    change = true;
                oldInput = input;
            }
            return input;
        }
        /// <summary>
        /// Metoda pro nalezení unárních operátorů, které nahrazuje sekvencí (0 znaménko 1)*
        /// </summary>
        /// <param name="input">Matematický výraz v infixové notaci</param>
        /// <param name="op">Unární operátor, který bude vyhledáván</param>
        /// <returns></returns>
        private string DetectUnaryOperator(string input, char op)
        {
                    StringBuilder output = new StringBuilder();
                    int offset = 1;
                    try
                    {
                        for (int i = 0; i < input.Length; i++)
                        {
                            if (input[i] == op)
                            {//znamenko na zacatku vyrazu nebo
                                //kdyz ( zavorka nebo eventualne znamenko
                                // pr sin(-x)
                                // nesmi se objevit casti vyrazu, ktere indikuji pritomnost dalsiho operandu
                                if ((i == 0) || (input[i - offset] != ')') && !char.IsDigit(input[i - offset]) && !char.IsLetter(input[i - offset]))
                                {
                                    output.Append("(0" + op + "1)*");
                                    while (char.IsDigit(input[i + 1]))
                                    {
                                        output.Append(input[i + 1]);
                                        i++;
                                    }
                                    while (char.IsLetter(input[i + 1]) || (input[i + 1] == ' ' || input[i + 1] == '(' || input[i + 1] == ')'))
                                    {
                                        output.Append(input[i + 1]);
                                        i++;
                                    }
                                    continue;
                                }
                                else
                                    output.Append(input[i]);
                                offset = 1;
                            }
                            else
                            {
                                output.Append(input[i]);
                                offset = 1;
                            }
                        }
                    }
                    catch { }
                    return output.ToString();
        }
        /// <summary>
        /// Převede desetinné číslo na tvar nezkráceného zlomku
        /// </summary>
        /// <param name="input">Matematický výraz v infixové notaci</param>
        /// <returns></returns>
        private string ConvertDecNumToFraction(string input)
        {
            input = input.Replace(',', '.');
            string pattern = "([0-9])+(\\.)([0-9])+";
            StringBuilder integerPart = new StringBuilder();
            StringBuilder decimalPart = new StringBuilder("1");
            Regex reg = new Regex(pattern);
            Match match = reg.Match(input);
            while (match.Success)
            {
                integerPart.Append(match.Groups[1].Value + match.Groups[3].Value);
                for (int i = 0; i < match.Groups[2].Value.Length; i++)
                {
                    decimalPart.Append("0");
                }
                input = reg.Replace(input,integerPart.ToString()+"/"+decimalPart.ToString(),1);
                match = reg.Match(input);
                integerPart.Clear();
                decimalPart.Clear();
                decimalPart.Append("1");
            }
            return input;

        }
        /// <summary>
        /// Metoda pro úpravu operátorů v infixové notaci
        /// </summary>
        /// <param name="input">Matematický výraz v infixové notaci</param>
        /// <returns></returns>
        private string EditSigned(string input)
        {
            Match match = null;
            List<string> Matches = new List<string>() { { "(-)(-)" }, { "(\\+)(\\+)" }, { "(-)(\\+)" }, { "(\\+)(-)" } };
            bool WasEditing = false;
            do
            {
                WasEditing = false;
                for (int i = 0; i < Matches.Count; i++)
                {
                    match = Regex.Match(input, Matches[i]);
                    if (match.Success)
                    {
                        input = input.Replace(match.ToString(), (i > 1) ? "-" : "+");
                        WasEditing = true;
                    }
                }
            }
            while (WasEditing != false);
            return input;
        }
        /// <summary>
        /// Provádí reverzi vstupního řetězce
        /// </summary>
        /// <param name="s">vstupní řetězec</param>
        /// <returns></returns>
        private string Reverse(string s)
        {
            char[] charArray = s.ToCharArray();
            Array.Reverse(charArray);
            return new string(charArray);
        }
        /// <summary>
        /// Metoda pro ošetření sekvencí výrazu ve tvaru ^-
        /// </summary>
        /// <param name="input">Matematický výraz v infixové notaci</param>
        /// <returns></returns>
        private string EditPowerMinusOperator(string input)
        { 
            StringBuilder output = new StringBuilder();
            output.Append(input);
            int position = -1;
            int zanoreniZavorky = 0;
            string temp = output.ToString();
            bool change = true;
            bool powerOp = false;
            while (temp.Contains("^-"))
            {
                position = temp.IndexOf("^-");
                output.Insert(position + 1, '(');
                position +=2;
                change = true;
                powerOp = false;
                while (change)
                {
                    try
                    {
                        change = false;
                        while (char.IsDigit(output[position + 1]))
                        {
                            position++;
                            change = true;
                        }
                        while (char.IsLetter(output[position + 1]) || (output[position + 1] == ' '))
                        {
                            position++;
                            change = true;
                        }
                        while (output[position + 1] == '(')
                        {
                            zanoreniZavorky++;
                            position++;
                            change = true;
                        }
                        while (output[position + 1] == ')')
                        {
                            zanoreniZavorky--;
                            position++;
                            change = true;
                        }
                        if (position == output.Length || (ListOfOperatorLasoc.Contains(output[position + 1])))
                        {
                            // pro vyrazy typu x^-2^-2 - > vraci x^(-2^(-2))
                            if (powerOp)
                            {
                                position++;
                                change = true;
                            }
                            else
                            {
                                if (zanoreniZavorky > 0)
                                {
                                    zanoreniZavorky--;
                                }
                                else
                                {
                                    output.Insert(position + 1, ')');
                                    change = false;

                                }
                                position++;
                            }
                        }
                        // pro vyrazy typu x^-3^2 -> metoda vraci x^(-3^2)
                        if (output[position + 1] == '^')
                        {
                            position++;
                            change = true;
                            powerOp = true;
                        }
                        else
                        {
                            powerOp = false;
                        }
                    }
                    catch (IndexOutOfRangeException)
                    {
                        output.Insert(position + 1, ')');
                        change = false;
                    }
                }
                temp = output.ToString();
            }
            return temp;
        }
        /// <summary>
        /// Metoda implementující Euklidův algoritmus, tj. nalezá největšího společného dělitele (pro krácení číselného zlomku)
        /// </summary>
        /// <param name="a">První celočíselný operand metody</param>
        /// <param name="b">Druhý celočíselný operand metody</param>
        /// <returns></returns>
        private int GCD(int a, int b)
        {
            while (a != 0 && b != 0)
            {
                if (a > b)
                    a %= b;
                else
                    b %= a;
            }
            if (a == 0)
                return b;
            else
                return a;
        }
        /// <summary>
        /// Metoda pro zjednodušení číselného zlomku
        /// </summary>
        /// <param name="postfix">Matematický výraz v postfixové notaci</param>
        /// <returns></returns>
        private string SimplifyFraction(string postfix)
        {
            List<string> listWithEmptyStrings = postfix.Split(' ').ToList();
            var listWithoutEmptyStrings = listWithEmptyStrings.Where(p => !string.IsNullOrWhiteSpace(p)).ToList();
            int nominator;
            int denominator;
            int gcd;
            for (int i = listWithoutEmptyStrings.IndexOf("/"); i > -1; i = listWithoutEmptyStrings.IndexOf("/", i + 1))
            {
                if (listWithoutEmptyStrings[i - 2].All(Char.IsDigit) && listWithoutEmptyStrings[i - 1].All(Char.IsDigit))
                {
                    nominator = Int32.Parse(listWithoutEmptyStrings[i - 2]);
                    denominator = Int32.Parse(listWithoutEmptyStrings[i - 1]);
                    gcd = GCD(nominator, denominator);
                    nominator /= gcd;
                    denominator /= gcd;
                    //odstranění zlomku, když jmenovatel je roven 1 
                    if (denominator == 1)
                    {
                        listWithoutEmptyStrings[i - 2] = nominator.ToString();
                        listWithoutEmptyStrings.RemoveRange(i - 1, 2);
                        i--;
                    }
                    else
                    {
                        listWithoutEmptyStrings[i - 2] = nominator.ToString();
                        listWithoutEmptyStrings[i - 1] = denominator.ToString();
                    }
                }
            }
            postfix = String.Join(" ", listWithoutEmptyStrings.ToArray());
            return postfix;
        }
        /// <summary>
        /// Metoda pro převedení vstupních výrazů (v infixové podobě) do Mathml kódu, využívá metodu
        ///pro převod do postfixové notace a následně využívá stromové konstrukce k získání jednoho výsledného
        /// mathml výrazu ( stromové konstrukce ve smyslu Huffmanova kódování), přičemž tato struktura je rychlejší
        /// než samotné huffmanovo kódování (binární operátor odmazává dva operandy(prvky) + operátor ze stromu (zrychlení),
        /// unární operátor vymazává jeden operand(prvek) + operátor)
        /// </summary>
        /// <param name="input">Výraz v infixové notaci</param>
        /// <param name="display">Typ Mathml zobrazení</param>
        /// <param name="WithHeader">Bool hodnota, je-li true, vrací metoda mathml výraz včetně Mathml hlavičky</param>
        /// <returns></returns>
        public string TextToMathml(string input,Mathml.Display display=Mathml.Display.block, bool WithHeader=true)
        {
            //predelat metodu
            input = RPN(input);
            input = input.Trim();
            input = input.Replace(".", ",");
            input = Regex.Replace(input, @"\s+", " ");
            List<string> result = input.Split(' ').ToList();
            StringBuilder sb = new StringBuilder();
            int countDig = -1;
            int i = 0;
            string firstOperand;
            string secondOperand;

            if (result.Count == 1)
            { 
                //result obsahuje pouze x nebo číslici/číslice
                countDig = result[0].Count(Char.IsDigit);
                if (result[0].All(Char.IsLetter))
                    result[0] = Mathml.Literal(result[0]);
                else if (result[0].All(Char.IsDigit))
                    result[0] = Mathml.Constant(double.Parse(result[0]));
             
            }
            while (result.Count > 1)
            {
                try
                {
                    if (result[i] == "+" || result[i] == "-" || result[i] == "*" || result[i] == "/" || result[i] == "^")
                    {
                        Tuple<string, string> output = BinaryOperatorMathml(result, i);
                        firstOperand = output.Item1;
                        secondOperand = output.Item2;
                        if (result[i] == "+" || result[i] == "-")
                        {
                            result[i] = id + firstOperand + Mathml.Mo(result[i]) + secondOperand;
                        }
                        if (result[i] == "*")
                        {
                            Tuple<string, string> operands = EditOperands(firstOperand, secondOperand,true);
                            result[i] = id + operands.Item1 + "<mo>*</mo>" + operands.Item2;
                        }
                        else if (result[i] == "/")
                        {
                            result[i] = id + Mathml.Frac(firstOperand, secondOperand);
                        }
                        else if (result[i] == "^")
                        {
                            Tuple<string, string> operands = EditOperands(firstOperand, secondOperand,false);
                            if (firstOperand.StartsWith(id + "<mfrac>"))
                            {
                                firstOperand = Mathml.LZ + firstOperand + Mathml.PZ;
                                result[i] = id + Mathml.Sup(firstOperand, operands.Item2);
                            }
                            else
                                result[i] = id + Mathml.Sup(operands.Item1, operands.Item2);
                        }
                        result.RemoveRange(i - 2, 2);
                        i = i - 2;
                    }
                    else if (result[i] == "sqrt" || (result[i].Length > 1 && result[i].All(Char.IsLetter)))
                    {
                        if (result[i] == "sqrt")
                        {
                            result[i] = id + Mathml.Sqrt(UnaryOperatorMathml(result, i));
                        }
                        else if (result[i].Length > 1 && result[i].All(Char.IsLetter)) //funkce
                        {
                            sb.Append(Mathml.Literal(result[i]) + Mathml.LZ);
                            sb.Append(UnaryOperatorMathml(result, i));
                            sb.Append(Mathml.PZ);
                            result[i] = id + sb.ToString();
                        }
                        result.RemoveRange(i - 1, 1);
                        i = i - 1;
                    }
                    sb.Clear();
                }
                catch 
                {
                    incorrectInput();
                    return string.Empty;
                }
                i++;
            }
            bool change = true;
            string compare = result[0];
            while (change)
            {
                compare=result[0];
                result[0] = ReplacingSubExpression(result[0]);
                if (compare == result[0])
                    change = false;
            }
            if (WithHeader)
                return Mathml.HeaderMath(display) + result[0] + Mathml.EndMath;
            else
                return result[0];
        }
        private Tuple<string,string> BinaryOperatorMathml(List<string> result,int i)
        {
            char id = Convert.ToChar(235);
            double num;
            StringBuilder sb = new StringBuilder();
            string s1 = string.Empty;
            string s2 = string.Empty;
            for (int j = 1; j < 3; j++)
            {
                if (result[i - j].All(Char.IsLetter))
                    sb.Append(Mathml.Literal(result[i - j]));
                else if (Double.TryParse(result[i - j], out num))
                    sb.Append(num.NumToMathml());
                else if (result[i - j][0] == id)
                    sb.Append(result[i - j]);
                if (j == 1)
                    s2 = sb.ToString();
                else
                    s1 = sb.ToString();
                sb.Clear();
            }
            return new Tuple<string, string>(s1, s2);
        }
        private string UnaryOperatorMathml(List<string> result, int i)
        {
            char id = Convert.ToChar(235);
            double num;
            StringBuilder sb = new StringBuilder();
            if (result[i - 1].All(Char.IsLetter))
                sb.Append(Mathml.Literal(result[i - 1]));
            else if (Double.TryParse(result[i - 1], out num))
                sb.Append(num.NumToMathml());
            else if (result[i - 1][0] == id)
                sb.Append(result[i - 1]);
            return sb.ToString();
        }
        /// <summary>
        /// metoda pro zjisteni poctu zavorek a poctu + a -
        /// Jestlize je vice operatoru nez zavorek (, tak metoda vraci true, jinak false
        /// Je-li true, tak v dalsich metodach bude dochazet k obaleni vyrazu zavorkami
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        private bool AddingBracket(string input)
        {
            int cnt = 0;
            int countOp = input.Where(x => (x == '+' || x == '-')).Count();
            int countBracket = input.Where(x => (x == '(')).Count();
            cnt = countOp - countBracket;
            if (cnt > 0)
                return true;
            else
                return false;
        }
        /// <summary>
        /// Metoda pro nahrazení podvýrazů v Mathml výrazů
        /// př. -- je nahrazeno +
        /// </summary>
        /// <param name="input">Mathml výraz</param>
        /// <returns></returns>
        private string ReplacingSubExpression(string input)
        {
            input = input.Replace("<mo>*</mo>", Mathml.Multiply);
            string pattern = "<msup><mrow><mrow><mo>\\(</mo>(ë)+<mn>0</mn>";
            input = Regex.Replace(input, pattern, "<msup><mrow><mrow><mo>(</mo>");
            pattern = "<msup><mrow><mrow><mo>\\(</mo><mn>0</mn>";
            input = Regex.Replace(input, pattern, "<msup><mrow><mrow><mo>(</mo>");
            input = Regex.Replace(input, "<mfrac><mrow><mo>\\+</mo>", "<mfrac><mrow>");
            input = input.Replace(id.ToString(), string.Empty);
            input = input.Replace(Mathml.Literal(pi.ToString()), Mathml.Literal(Symbols.pi));
            input = input.Replace(Mathml.LZ + Mathml.Constant(0) + Mathml.Minus + Mathml.Constant(1) + Mathml.PZ + Mathml.Multiply, Mathml.Minus);
            input = input.Replace(Mathml.LZ + Mathml.Constant(0) + Mathml.Plus + Mathml.Constant(1) + Mathml.PZ + Mathml.Multiply, string.Empty);
            input = input.Replace(Mathml.LZ + Mathml.Constant(0) + Mathml.Minus + Mathml.Constant(1) + Mathml.PZ, Mathml.Minus);
            input = input.Replace(Mathml.Constant(0) + Mathml.Minus + Mathml.Constant(1), Mathml.Minus + Mathml.Constant(1));
            input = input.Replace(Mathml.Constant(0) + Mathml.Plus + Mathml.Constant(1), Mathml.Constant(1));
            input = input.Replace(Mathml.Plus + Mathml.Minus, Mathml.Minus);
            input = input.Replace(Mathml.Minus + Mathml.Minus, Mathml.Plus);
            input = input.Replace(Mathml.Minus + Mathml.Plus, Mathml.Minus);
            input = input.Replace(Mathml.Plus + Mathml.Plus, Mathml.Plus);
            input = input.Replace(Mathml.Multiply + Mathml.Plus, Mathml.Multiply);
       //     input = input.Replace(Mathml.Multiply + Mathml.Minus, Mathml.Multiply);
            if (input.StartsWith(Mathml.Plus))
                input = input.Remove(0, Mathml.Plus.Length);
            return input;
        }
        /// <summary>
        /// Pomocná metoda pro případné obalení výrazů závorkami, využívá metodu AddingBracket
        /// </summary>
        /// <param name="firstOperand"></param>
        /// <param name="secondOperand"></param>
        /// <returns></returns>
        private Tuple<string, string> EditOperands(string firstOperand, string secondOperand,bool LeftAsoc)
        {
            string temp;
            string pattern = Mathml.LZ + Mathml.Constant(0) + Mathml.Minus + Mathml.Constant(1) + Mathml.PZ + "<mo>*</mo>";
            string pattern2 = Mathml.LZ + Mathml.Constant(0) + Mathml.Minus + Mathml.Constant(1) + Mathml.PZ;
            if ((firstOperand.Contains("+") || (firstOperand.Contains("-")) && AddingBracket(firstOperand)))
                firstOperand = Mathml.LZ + firstOperand + Mathml.PZ;
            if ((secondOperand.Contains("+") || secondOperand.Contains("-")) && AddingBracket(secondOperand))
                secondOperand = Mathml.LZ + secondOperand + Mathml.PZ;
            temp = secondOperand.Replace(id.ToString(), string.Empty);
            if (temp == Mathml.LZ + Mathml.Constant(0) + Mathml.Minus + Mathml.Constant(1) + Mathml.PZ)
            {
                temp = firstOperand;
                firstOperand = secondOperand;
                secondOperand = temp;
            }           
            if (LeftAsoc && temp.StartsWith(pattern))
	             {
	                 temp = temp.Remove(0, pattern.Length);
	                 firstOperand = pattern + firstOperand;
	                 secondOperand = temp;
	             }
	       return Tuple.Create(firstOperand, secondOperand);
        }
        /// <summary>
        /// Metoda pro řešení matematických výrazů obsahující ...^(-....^
        /// Metoda vrací ...^((0)-...
        /// Umožňuje správně zobrazit vztahy obsahující dva exponenty z nichž první je záporný a CELÝ ohraničen závorkou
        /// Bez metody je vstup renderován do Mathml bez závorky
        /// tj př. vstup = x^(-2)^(-3) -> výstup = x^(-2)^-3 nikoli (a špatně) x^-2^-3 
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        private string PowerOperatorBracketMinus(string input)
        {
            string pattern = "(\\^[\\(]+)(-[a-zA-Z0-9\\+\\*-/]+\\)+)(\\^)";
            Match match = Regex.Match(input, pattern);
            while (match.Success)
            {
            input = Regex.Replace(input, pattern, "$1(0)$2$3");
            match = Regex.Match(input, pattern);
            }
            pattern = "([\\(]+)(-[a-zA-Z0-9\\+\\*-/]+\\)+)(\\^)";
            match = Regex.Match(input, pattern);
            while (match.Success)
            {
                input = Regex.Replace(input, pattern, "$1(0)$2$3");
                match = Regex.Match(input, pattern);
            }
            return input;
        }
    }
}
